/*
 * @[H]:  Copyright (c) 2021 Phytium Information Technology, Inc. 
 * 
 *  SPDX-License-Identifier: Apache-2.0. 
 * 
 * @Date: 2021-07-15 10:14:37
 * @LastEditTime: 2021-09-06 14:54:53
 * @Description:  Description of file
 * @Modify History: 
 * * * Ver   Who        Date         Changes
 * * ----- ------     --------    --------------------------------------
 */

#include "ft_can.h"
#include "f_iomux.h"
#include "ft_can_hw.h"
#include "interrupt.h"
// #include "gicv3.h"
#include "parameters.h"
#include "ft_debug.h"
#include <string.h>

#define FCAN_TEST_DEBUG_TAG "FCAN_TEST"
#define FCAN_TEST_ERROR(format, ...) FT_DEBUG_PRINT_E(FCAN_TEST_DEBUG_TAG, format, ##__VA_ARGS__)
#define FCAN_TEST_DEBUG_I(format, ...) FT_DEBUG_PRINT_I(FCAN_TEST_DEBUG_TAG, format, ##__VA_ARGS__)
#define FCAN_TEST_DEBUG_W(format, ...) FT_DEBUG_PRINT_W(FCAN_TEST_DEBUG_TAG, format, ##__VA_ARGS__)
#define FCAN_TEST_DEBUG_E(format, ...) FT_DEBUG_PRINT_E(FCAN_TEST_DEBUG_TAG, format, ##__VA_ARGS__)

#define FCAN_TEST_BANDRATE 250000
#define FCAN_SEND_ID 0x32
#define FCAN_SEND_LENGTH 4
#define FCAN_USE_EXSTANDARD 1

static u32 SendFrame(FCan *instance_p);
static u32 RecvFrame(FCan *instance_p);
static void FCanTxIrqCallback(void *args);
static void FCanRxIrqCallback(void *args);
static void FCanErrorCallback(void *args, u32 error_status, u32 txerr_cnt, u32 rxerr_cnt);
static void FCanIrqHandler(s32 vector, void *param);
/************************** Variable Definitions ****************************/

static u32 tx_is_done;
static u32 recv_is_done;
FCan can0;
FCan can1;

static int FCanHwInit(void)
{
    u32 status = 0;
    struct FCanBittiming arb_bittiming;
    struct FCanBittiming data_bittiming;
    u32 frame_type;

    FIomuxSetFun(FCAN_IOMUX_CAN0_TX_OFFSET, FUN1);
    FIomuxSetFun(FCAN_IOMUX_CAN0_RX_OFFSET, FUN1);
    FIomuxSetFun(FCAN_IOMUX_CAN1_TX_OFFSET, FUN1);
    FIomuxSetFun(FCAN_IOMUX_CAN1_RX_OFFSET, FUN1);

    status = FCanCfgInitialize(&can0, FCanLookupConfig(0));
    if (status != FCAN_SUCCESS)
    {
        return status;
    }

    status = FCanCfgInitialize(&can1, FCanLookupConfig(1));
    if (status != FCAN_SUCCESS)
    {
        return status;
    }

    /* Set the baudrate of the arb domain */
    memset(&arb_bittiming, 0, sizeof(arb_bittiming));
    arb_bittiming.bitrate = FCAN_TEST_BANDRATE;
    FCanCalcBittiming(&arb_bittiming, FCAN_CALC_ARB_TIMING);
    /* Set the baudrate of the data domain */
    memset(&data_bittiming, 0, sizeof(data_bittiming));
    data_bittiming.bitrate = FCAN_TEST_BANDRATE;
    FCanCalcBittiming(&data_bittiming, FCAN_CALC_DATA_TIMING);

    FCanSetTiming(&can0, &arb_bittiming, &data_bittiming);
    FCanSetTiming(&can1, &arb_bittiming, &data_bittiming);

    /* set filter */
#if (FCAN_USE_EXSTANDARD == 1)
    frame_type = FCAN_EXTENDARD_FRAME;
#else
    frame_type = FCAN_STANDARD_FRAME;
#endif

    FCanIdMaskFilterSet(&can0, 0, frame_type, 0, 0xFFFFFFFF);
    FCanIdMaskFilterSet(&can0, 1, frame_type, 0, 0xFFFFFFFF);
    FCanIdMaskFilterSet(&can0, 2, frame_type, 0, 0xFFFFFFFF);
    FCanIdMaskFilterSet(&can0, 3, frame_type, 0, 0xFFFFFFFF);
    FCanIdMaskFilterEnable(&can0);

    FCanIdMaskFilterSet(&can1, 0, frame_type, 0, 0xFFFFFFFF);
    FCanIdMaskFilterSet(&can1, 1, frame_type, 0, 0xFFFFFFFF);
    FCanIdMaskFilterSet(&can1, 2, frame_type, 0, 0xFFFFFFFF);
    FCanIdMaskFilterSet(&can1, 3, frame_type, 0, 0xFFFFFFFF);
    FCanIdMaskFilterEnable(&can1);
    return status;
}

int FCanPolledExample(void)
{
    u32 status = 0;

#if (FCAN_USE_EXSTANDARD == 1)
    FCAN_TEST_DEBUG_I("Can  transmit exstandard frame in poll method is start ");

#else
    FCAN_TEST_DEBUG_I("Can  transmit standard frame in poll method is start ");
#endif

    FCAN_TEST_DEBUG_I("Can baudrate is %d bits/s", FCAN_TEST_BANDRATE);

    status = FCanHwInit();

    if (status != FCAN_SUCCESS)
    {
        FCAN_TEST_DEBUG_E("FCanHwInit is error");
        return status;
    }

    FCanEnable(&can0);
    FCanEnable(&can1);

    FCAN_TEST_DEBUG_I("Can0 start to poll send");
    status = SendFrame(&can0);
    if (status != 0)
    {
        FCAN_TEST_DEBUG_E("Can 0 is send error");
        return status;
    }

    status = RecvFrame(&can1);
    if (status != 0)
    {
        FCAN_TEST_DEBUG_E("Can 1 is recv error");
        return status;
    }

    FCAN_TEST_DEBUG_I("Can1 start to poll send");

    status = SendFrame(&can1);
    if (status != 0)
    {
        FCAN_TEST_DEBUG_E("Can 1 is send error");
        return status;
    }

    status = RecvFrame(&can0);
    if (status != 0)
    {
        FCAN_TEST_DEBUG_E("Can 0 is recv error");
        return status;
    }

    FCanDisable(&can0);
    FCanDisable(&can1);
    return status;
}

static u32 SendFrame(FCan *instance_p)
{
    u32 i;
    u32 status;
    struct FCanFrame frame = {0};

    frame.canid = FCAN_SEND_ID;

#if (FCAN_USE_EXSTANDARD == 1)
    frame.canid |= CAN_EFF_FLAG;
#else
    frame.canid &= CAN_SFF_MASK;
#endif

    frame.candlc = FCAN_SEND_LENGTH;
    for (i = 0; i < frame.candlc; i++)
    {
        frame.data[i] = i;
    }

    while (1 == FCAN_TX_FIFO_FULL(instance_p))
        ;

    status = FCanSend(instance_p, &frame);

    return status;
}

static u32 RecvFrame(FCan *instance_p)
{
    u32 i;
    u32 status, error_flg = 0;

    struct FCanFrame frame = {0};
    while (FCAN_RX_FIFO_EMPTY(instance_p))
        ;
    status = FCanRecv(instance_p, &frame);
    if (FCAN_SUCCESS == status)
    {

#if (FCAN_USE_EXSTANDARD == 1)
        if (frame.canid != (FCAN_SEND_ID | CAN_EFF_FLAG))
        {
            FCAN_TEST_DEBUG_E("canid is %x", frame.canid);
            error_flg++;
        }
#else
        if (frame.canid != FCAN_SEND_ID)
        {
            error_flg++;
        }
#endif

        if (frame.candlc != FCAN_SEND_LENGTH)
        {
            FCAN_TEST_DEBUG_E("Can dlc is %d ", frame.candlc);
            error_flg++;
        }

        for (i = 0; i < frame.candlc; i++)
        {
            if (frame.data[i] != i)
            {
                error_flg++;
            }
        }
    }

    if (error_flg == 0)
    {
        FCAN_TEST_DEBUG_I("Can%d recv is ok", instance_p->config.instanceid);
    }
    else
    {
        FCAN_TEST_DEBUG_E("Can%d recv is error", instance_p->config.instanceid);
    }
    return status;
}

int FCanIrqExample(void)
{
    u32 status = 0;
    struct FCanBittiming arb_bittiming;
    struct FCanBittiming data_bittiming;

    tx_is_done = 0;
    recv_is_done = 0;

#if (FCAN_USE_EXSTANDARD == 1)
    FCAN_TEST_DEBUG_I("Can  transmit exstandard frame in irq method is start ");
#else
    FCAN_TEST_DEBUG_I("Can  transmit standard frame in irq method is start ");
#endif

    FCAN_TEST_DEBUG_I("Can baudrate is %d bits/s", FCAN_TEST_BANDRATE);

    FCanHwInit();

    FCanSetHandler(&can0, FCAN_HANDLER_SEND, FCanTxIrqCallback, (void *)&can0);
    FCanSetHandler(&can0, FCAN_HANDLER_RECV, FCanRxIrqCallback, (void *)&can0);
    FCanSetHandler(&can0, FCAN_HANDLER_ERROR, FCanErrorCallback, (void *)&can0);

    FCanSetHandler(&can1, FCAN_HANDLER_SEND, FCanTxIrqCallback, (void *)&can1);
    FCanSetHandler(&can1, FCAN_HANDLER_RECV, FCanRxIrqCallback, (void *)&can1);
    FCanSetHandler(&can1, FCAN_HANDLER_ERROR, FCanErrorCallback, (void *)&can1);

    FCanEnable(&can0);
    FCanEnable(&can1);

    InterruptSetPriority(can0.config.irq_num, 0);
    InterruptInstall(can0.config.irq_num, (IrqHandler)FCanIrqHandler, &can0, "can0");
    InterruptUmask(can0.config.irq_num);

    InterruptSetPriority(can1.config.irq_num, 0xa0);
    InterruptInstall(can1.config.irq_num, (IrqHandler)FCanIrqHandler, &can1, "can1");
    InterruptUmask(can1.config.irq_num);

    SendFrame(&can0);

    while ((tx_is_done != 1) || (recv_is_done != 1))
        ;
    tx_is_done = 0;
    recv_is_done = 0;
    RecvFrame(&can1);

    SendFrame(&can1);

    while ((tx_is_done != 1) || (recv_is_done != 1))
        ;
    RecvFrame(&can0);

    FCanDisable(&can0);
    FCanDisable(&can1);
    return 0;
}

static void FCanTxIrqCallback(void *args)
{
    FCan *instance_p = (FCan *)args;
    FCAN_TEST_DEBUG_I("Can%d irq send frame is ok", instance_p->config.instanceid);
    tx_is_done = 1;
}

static void FCanRxIrqCallback(void *args)
{
    recv_is_done = 1;
}

static void FCanErrorCallback(void *args, u32 error_status, u32 txerr_cnt, u32 rxerr_cnt)
{
    FCan *instance_p = (FCan *)args;
    FCAN_TEST_DEBUG_E("Can %d is under error", instance_p->config.instanceid);
    FCAN_TEST_DEBUG_E("error_status is %x", error_status);
    FCAN_TEST_DEBUG_E("txerr_cnt is %x", txerr_cnt);
    FCAN_TEST_DEBUG_E("rxerr_cnt is %x", rxerr_cnt);
}

static void FCanIrqHandler(s32 vector, void *param)
{
    FCanIntrHandler(param);
}